#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include "ring-buffer.h"

void _memcpy(void *_dst, void const *const _src, size_t size)
{
    uint8_t *dst = (uint8_t *)_dst;
    uint8_t const * const src = (uint8_t *)_src;
    for (size_t i = 0; i < size; i++)
    {
        dst[i] = src[i];
    }
}

void __writeData(CircularBuffer *buffer, void const *const data, const size_t dataSize)
{
    size_t spaceToEnd = BUFFER_SIZE - buffer->rear; // 从写指针到缓冲区末尾的空间大小

    if (dataSize <= spaceToEnd)
    {
        // 数据可以一次性写入
        _memcpy(buffer->data + buffer->rear, data, dataSize);
    }
    else
    {
        // 数据需要分两次写入
        _memcpy(buffer->data + buffer->rear, data, spaceToEnd);
        _memcpy(buffer->data, (char *)data + spaceToEnd, dataSize - spaceToEnd);
    }

    // 因为仅写者使用 rear
    buffer->rear = (buffer->rear + dataSize) % BUFFER_SIZE;
}

// 向环形缓冲区写入数据
DataHeader writeData(CircularBuffer *buffer, void const *const data, size_t dataSize)
{
    DataHeader header = {
        .len = 0};

    if (buffer->count + dataSize + sizeof(DataHeader) > BUFFER_SIZE)
    {
        // printf("缓冲区已满，无法写入数据\n");
        return header;
    }

    header.len = dataSize;

    // 写入数据头
    __writeData(buffer, &header, sizeof(DataHeader));
    // 写入数据内容
    __writeData(buffer, data, header.len);
    
    __sync_synchronize();
    __sync_fetch_and_add(&buffer->count, dataSize + sizeof(DataHeader));
    return header;
}

void __readData(CircularBuffer *buffer, void *data, const size_t size_2_read)
{
    // 读取数据内容
    if (buffer->front + size_2_read <= BUFFER_SIZE)
    {
        // 数据可以一次性读取
        _memcpy(data, buffer->data + buffer->front, size_2_read);
    }
    else
    {
        // 数据需要分两次读取
        size_t spaceToEnd = BUFFER_SIZE - buffer->front;
        _memcpy(data, buffer->data + buffer->front, spaceToEnd);
        _memcpy((char *)data + spaceToEnd, buffer->data, size_2_read - spaceToEnd);
    }

    // 因为仅读者使用 front
    buffer->front = (buffer->front + size_2_read) % BUFFER_SIZE;
}

// 从环形缓冲区读取数据
bool readData(CircularBuffer *buffer, void *data, DataHeader *header)
{
    // 读前加内存屏障是为了保证是从内存里面读数据的
    // riscv 指令的内存屏障是可以保证这一点的，其他体系结构似乎不能够使用该方法
    __sync_synchronize();

    if (buffer->count == 0 || NULL == data || header == NULL)
    {
        // printf("缓冲区为空，无法读取数据\n");
        return false;
    }

    // 读取数据头
    __readData(buffer, header, sizeof(DataHeader));

    // 复制数据内容到新的内存中
    __readData(buffer, data, header->len);

    __sync_fetch_and_sub(&buffer->count, header->len + sizeof(DataHeader));
    return true;
}
